package com.smartcommunity.service.facelib.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.smartcommunity.api.engine.EngineApi;
import com.smartcommunity.api.faceLib.FaceLibApi;
import com.smartcommunity.bean.constant.ShenWangLibPrefix;
import com.smartcommunity.bean.enumeration.ResultCode;
import com.smartcommunity.bean.model.Pager;
import com.smartcommunity.bean.model.Result;
import com.smartcommunity.dao.facelib.FaceLibDao;
import com.smartcommunity.entity.facelib.*;
import com.smartcommunity.entity.tag.Tag;
import com.smartcommunity.faceengine.FaceEngineService;
import com.smartcommunity.lis.BimgClientPool;
import com.smartcommunity.service.facelib.FaceLibService;
import com.smartcommunity.service.tag.TagService;
import com.smartcommunity.utils.StaticToolConst;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.DigestUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
import static org.apache.commons.lang3.StringUtils.isNotBlank;

/**
 * @version V1.0
 * @ClassName: FaceLibServiceImpl
 * @Description: 人脸库及库人员信息service类
 * @author: tianzongbing
 * @Date: 2020/02/17
 * @Company:
 */
@Service
@Slf4j
public class FaceLibServiceImpl implements FaceLibService {

    @Autowired
    TagService tagService;

    @Autowired
    FaceLibDao faceLibDao;

    @Autowired
    FaceLibApi faceLibApi;

    @Autowired
    EngineApi engineApi;

    @Autowired
    private BimgClientPool lis;

    @Autowired
    FaceEngineService faceEngineService;

    Cache<String, Tag> TagCache = CacheBuilder.newBuilder()
            .expireAfterWrite(2, TimeUnit.MINUTES)
            .weakValues().weakKeys().build();

    /**
     * 人脸库列表
     *
     * @param faceLib
     * @return
     */
    @Override
    public Pager<FaceLib> listFaceLibs(FaceLib faceLib) {
        PageHelper.startPage(faceLib.getPageNumber(), faceLib.getPageSize());
        List<FaceLib> entryList = faceLibDao.selectFaceLib(faceLib);
        int totalNum = (int) ((Page<FaceLib>) entryList).getTotal();
        Pager<FaceLib> pageData = new Pager(faceLib.getPageNumber(), faceLib.getPageSize(), totalNum);
        pageData.setList(entryList);
        log.info("人脸库，分页查询FaceLib，查询参数:{}，查询结果数量:{}"
                , faceLib, Optional.ofNullable(pageData.getList()).map(List::size).orElse(0));
        return pageData;
    }

    @Override
    public List<FaceLib> findFaceLibByLibIds(String libId) {
        Assert.hasText(libId, "libId不能为空");

        FaceLib query = new FaceLib();
        query.setLibId(libId);
        return faceLibDao.selectFaceLib(query);
    }

    @Override
    public int addFaceLib(FaceLib faceLib) {

        int i = faceLibDao.insertFaceLib(faceLib);
        log.info("人脸库，新增FaceLib，LibId:{}，操作结果:{}", faceLib.getLibId(), i);
        return i;
    }

    @Override
    public int updateFaceLib(FaceLib faceLib) {
        FaceLib orgLib = faceLibDao.selectLibById(faceLib.getLibId());
        int i = faceLibDao.updateFaceLib(faceLib);
        faceLibDao.updateTagByaLib(faceLib,orgLib);
        log.info("人脸库，更新FaceLib，LibId:{}，操作结果:{}", faceLib.getLibId(), i);
        return i;
    }

    /**
     * 更新人脸库人员数量
     *
     * @param libId 人脸库编号
     * @return 0/1
     */
    @Override
    public int updateFaceLibTotal(String libId) {
        FaceLib lib = new FaceLib();
        lib.setLibId(libId);
        int i = faceLibDao.updateFaceLibTotal(lib);
        log.info("人脸库，更新FaceLib的total数量,LibId:{},更新结果:{}条", libId, i);
        return i;
    }

    /**
     * 删除人脸库
     *
     * @param faceLib 人脸库，其中libId不能为空，可以多个Id用逗号分隔
     */
    @Override
    public Result deleteFaceLib(FaceLib faceLib) {
        //校验人脸库下是否有人员
        String libIds[] = faceLib.getLibId().split(",");
        for(String libId : libIds){
            FaceLibPerson faceLibPerson = new FaceLibPerson();
            faceLibPerson.setLibId(libId);
            int count = faceLibDao.countFaceLibPerson(faceLibPerson);
            if(count>0){
                FaceLib lib = new FaceLib();
                lib.setLibId(libId);
                List<FaceLib> list = faceLibDao.selectFaceLib(lib);
                if(CollectionUtils.isNotEmpty(list)){
                    String libName = list.get(0)!=null?list.get(0).getLibName():libId;
                    return Result.error(ResultCode.FACE_LIB_HAVE_PEOPLE.code(),String.format(ResultCode.FACE_LIB_HAVE_PEOPLE.msg(),libName));
                }else{
                    return Result.error(ResultCode.DATA_LOSE);
                }
            }
        }

        int i = faceLibDao.deleteFaceLibByIds(faceLib);
        log.info("人脸库，删除FaceLib:{}条", i);

        int pint = this.deleteFaceLibPersonByLibId(faceLib.getLibId());
        log.info("人脸库，级联删除人脸库所属FaceLibPerson:{}条", pint);

        //删除人员库同步到引擎
        for(String libId : libIds){
            Map<String,Object> map = Maps.newHashMap();
            //libId 可能多个 eg:1,2,3
            map.put("libId",ShenWangLibPrefix.getLibPrefix()+libId);
            Result result = faceLibApi.deleteLib(map);
            log.info("人脸库，删除人员库同步到引擎,参数:{}，操作结果:{}", map.toString(),result.getResultCode());
        }
        return Result.ok();
    }

    //----------------------------------

    @Override
    public Pager<FaceLibPerson> listFaceLibPerson(FaceLibPerson faceLibPerson) {
//        Integer total = faceLibDao.countFaceLibPerson(faceLibPerson);
        PageHelper.startPage(faceLibPerson.getPage(), faceLibPerson.getPageSize());
        List<FaceLibPerson> entryList = faceLibDao.selectFaceLibPerson(faceLibPerson);
        int totalNum = (int) ((Page<FaceLibPerson>) entryList).getTotal();
        Pager<FaceLibPerson> personPage = new Pager(faceLibPerson.getPage(), faceLibPerson.getPageSize(), totalNum);
        personPage.setList(entryList);

        log.info("人脸库，分页查询FaceLibPerson，查询参数:{}，查询结果数量:{}"
                , faceLibPerson, Optional.ofNullable(personPage.getList()).map(List::size).orElse(0));

        if (isNotEmpty(entryList)) {
            // 加载人员库人员与标签的关联记录
            List<String> facePersonIdList = entryList.stream()
                    .map(FaceLibPerson::getId).collect(Collectors.toList());
            FaceLibPersonTag tagParam = new FaceLibPersonTag();
            tagParam.setFacePersonId(StaticToolConst.COMMA_JOINER.join(facePersonIdList));
            List<FaceLibPersonTag> tagList = faceLibDao.selectTagList(tagParam);
            final Map<String, List<FaceLibPersonTag>> personMap = Optional.ofNullable(tagList).map(List::stream)
                    .map(s -> s.collect(Collectors.groupingBy(FaceLibPersonTag::getFacePersonId))).orElse(Maps.newHashMap());
            personPage.getList().forEach(p -> p.setTagList(personMap.get(p.getId())));

            // 加载标签实体列表
            Set<String> tagIds = Optional.ofNullable(tagList).map(List::stream)
                    .map(s -> s.map(FaceLibPersonTag::getTagId)).get().collect(Collectors.toSet());
            Map<String, Tag> tagEntityMap = listTagEntityMap(tagIds);
            for (FaceLibPerson person : personPage.getList()) {
                if (CollectionUtils.isEmpty(person.getTagList())) {
                    continue;
                }
                for (FaceLibPersonTag pt : person.getTagList()) {
                    Optional.ofNullable(tagEntityMap.get(pt.getTagId()))
                            .ifPresent(person.getTagEntityList()::add);
                }
            }

            log.info("人脸库，分页查询FaceLibPerson，查询后填充tagList，查询结果数量:{}"
                    , faceLibPerson, Optional.ofNullable(personPage.getList()).map(List::size).orElse(0));

        }
        return personPage;
    }

    @Override
    public List<FaceLibPerson> listLibPerson(FaceLibPerson faceLibPerson) {
//        Integer total = faceLibDao.countFaceLibPerson(faceLibPerson);
        List<FaceLibPerson> entryList = faceLibDao.selectFaceLibPerson(faceLibPerson);
        if (isNotEmpty(entryList)) {
            // 加载人员库人员与标签的关联记录
            List<String> facePersonIdList = entryList.stream()
                    .map(FaceLibPerson::getId).collect(Collectors.toList());
            FaceLibPersonTag tagParam = new FaceLibPersonTag();
            tagParam.setFacePersonId(StaticToolConst.COMMA_JOINER.join(facePersonIdList));
            List<FaceLibPersonTag> tagList = faceLibDao.selectTagList(tagParam);
            final Map<String, List<FaceLibPersonTag>> personMap = Optional.ofNullable(tagList).map(List::stream)
                    .map(s -> s.collect(Collectors.groupingBy(FaceLibPersonTag::getFacePersonId))).orElse(Maps.newHashMap());
            entryList.forEach(p -> p.setTagList(personMap.get(p.getId())));

            // 加载标签实体列表
            Set<String> tagIds = Optional.ofNullable(tagList).map(List::stream)
                    .map(s -> s.map(FaceLibPersonTag::getTagId)).get().collect(Collectors.toSet());
            Map<String, Tag> tagEntityMap = listTagEntityMap(tagIds);
            for (FaceLibPerson person : entryList) {
                if (CollectionUtils.isEmpty(person.getTagList())) {
                    continue;
                }
                for (FaceLibPersonTag pt : person.getTagList()) {
                    Optional.ofNullable(tagEntityMap.get(pt.getTagId()))
                            .ifPresent(person.getTagEntityList()::add);
                }
            }
        }
        return entryList;
    }

    /**
     * 根据
     *
     * @param tagIds 标签ID集合
     * @return 标签Map。k->标签ID，v->标签对象
     */
    private synchronized Map<String, Tag> listTagEntityMap(Collection<String> tagIds) {

        // 当缓存为空或者不完全满足查询时，重新加载标签
        boolean cachedAll = TagCache.size() > 0 && TagCache.asMap().keySet().containsAll(tagIds);
        if (!cachedAll) {
            log.info("查询的tagId中包含未曾缓存的标签，更新缓存前的缓存数量:{}", TagCache.size());
            loadTagEntityCache();
            log.info("查询的tagId中包含未曾缓存的标签，更新缓存后的缓存数量:{}", TagCache.size());
        }
        return Maps.newHashMap(TagCache.asMap());
    }

    private void loadTagEntityCache() {
        // 删除所有缓存
        TagCache.invalidateAll();

        // 加载所有标签
        AtomicInteger page = new AtomicInteger(1);
        Map<String, Object> param = ImmutableMap.of("targetType", 1);
        while (page.get() > 0) {
            Pager<Tag> tagPage = tagService.getTagList(param, page.get(), 1000);
            Map<String, Tag> tagEntityMap = Optional.ofNullable(tagPage).map(Pager::getList).map(List::stream).get()
                    .collect(Collectors.toMap((t) -> Objects.toString(t.getId()), Function.identity()));
            TagCache.putAll(tagEntityMap);

            // 是否需要继续查询
            if (tagPage.getIsMore() == 1) {
                page.incrementAndGet();
            } else {
                page.set(0); // 当所有分页都查询完后，停止加载
            }
        }
    }

    @Override
    public int addFaceLibPerson(FaceLibPerson faceLibPerson) {
        return baseAddFaceLibPerson(faceLibPerson, true);
    }

    @Transactional
    public int baseAddFaceLibPerson(FaceLibPerson faceLibPerson, boolean ifUpdateFaceLibTotal) {
        int i = faceLibDao.insertFaceLibPerson(faceLibPerson);

        FaceLib lib = faceLibDao.selectLibById(faceLibPerson.getLibId());
        if (lib == null) {
            return 0;
        }

        log.info("人脸库，新增FaceLibPerson，操作结果:{}", i);

        FaceLibPersonTag libTag = new FaceLibPersonTag();
        libTag.setTagId(lib.getType());
        libTag.setLibId(lib.getLibId());
        libTag.setFacePersonId(faceLibPerson.getId());

        AtomicBoolean isHaveTag = new AtomicBoolean(false);

        // 添加人员标签关系
        if (isNotEmpty(faceLibPerson.getTagList())) {
            faceLibPerson.getTagList().stream()
                    .filter(tag -> isNotBlank(tag.getTagId()))
                    .forEach(tag -> {
                        if (tag.getTagId().equals(libTag.getTagId())) {
                            isHaveTag.set(true);
                        }
                        tag.setFacePersonId(faceLibPerson.getId());
                        tag.setLibId(faceLibPerson.getLibId());
                    });

            if (!isHaveTag.get()) {
                faceLibPerson.getTagList().add(libTag);
            }
        } else {
            faceLibPerson.setTagList(new ArrayList<>());
            faceLibPerson.getTagList().add(libTag);
        }

        int tagCnt = faceLibDao.insertTagList(faceLibPerson);
        log.info("人脸库，新增FaceLibPerson后，添加人员标签关系。操作结果:{}", tagCnt);

        // 更新人脸库人员数量
        if (ifUpdateFaceLibTotal) {
            updateFaceLibTotal(faceLibPerson.getLibId());
            log.info("人脸库，新增FaceLibPerson后，更新关联FaceLib的total数量。LibId:{}，操作结果:{}", faceLibPerson.getLibId(), i);
        }

        addOrUpdateToCompreFace(faceLibPerson);

        return i;
    }

    /**
     * 增加人脸特征记录并同步到引擎的布控库中
     *
     * @param faceLibPerson
     */
    private void addOrUpdateToCompreFace(FaceLibPerson faceLibPerson) {
        // 增加人脸特征记录并同步到引擎的布控库中
        if (StringUtils.isNotBlank(faceLibPerson.getFaceImageUrl())) {
            String baseStr = null;
            try {
                byte[] bytes = lis.downLoad(faceLibPerson.getFaceImageUrl());
                baseStr = Base64.getEncoder().encodeToString(bytes);
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException("图片下载失败");
            }

            Map<String, Object> subjectMap = new HashMap<>();
            Map<String, Object> subjectFaceMap = new HashMap<>();
            subjectFaceMap.put("file", baseStr);
            subjectMap.put("subject", faceLibPerson.getIdCardNo());
            engineApi.deleteSubject(faceLibPerson.getIdCardNo());
            Result<Object> objectResult = engineApi.addSubject(subjectMap);
            if (objectResult.getResultCode() == 200) {
                Result<Object> result = engineApi.addFacesByBase64(faceLibPerson.getIdCardNo(), subjectFaceMap);
                if (result.getResultCode() != 200) {
                    throw new RuntimeException("引擎添加人脸照片失败：" + JSONObject.toJSONString(result.getResultMessage()));
                }
            } else {
                throw new RuntimeException("引擎添加人脸信息失败：" + JSONObject.toJSONString(objectResult.getResultMessage()));
            }
        }
    }


    /**
     * 目前用于xlsx模板批量导入人员信息
     *
     * @param list 人员信息。其中中文标签名存于tagEntityList中tagEntity.tagName
     * @return
     */
    @Override
    public int addFaceLibPersonList(List<FaceLibPerson> list) {
        Assert.notEmpty(list, "批量添加人员库人员，参数集合不能为空");

        // libId获取和简单校验
        Set<String> libIds = list.stream().map(FaceLibPerson::getLibId).collect(Collectors.toSet());
        Assert.notEmpty(libIds, "批量添加人员库人员，参数集合中libId不能为空");
        Assert.isTrue(libIds.size() == 1, "批量添加人员库人员，参数集合中libId不相等");
        // 更新人脸库人员数量
        String libId = libIds.iterator().next();
        FaceLib lib = faceLibDao.selectLibById(libId);
        Assert.isTrue(lib != null, "批量添加库不存在");
        FaceLibPersonTag libTag = new FaceLibPersonTag();
        libTag.setTagId(lib.getType());
        libTag.setLibId(lib.getLibId());
        // 重新加载标签缓存
        loadTagEntityCache();

        // 返回值
        int resultCnt = 0;

        // 填充参数，新增人员及关联标签
        Map<String, Integer> tagNameMap = TagCache.asMap().values().stream()
                .collect(Collectors.toMap(Tag::getTagName, Tag::getId, (oldVal, newVal) -> newVal));
        Set<String> missTagNames = Sets.newHashSet();
        for (FaceLibPerson person : list) {


            if (CollectionUtils.isNotEmpty(person.getTagEntityList())) {
                person.getTagEntityList().stream()
                        .map(Tag::getTagName).filter(StringUtils::isNotBlank)
                        .collect(Collectors.toSet())
                        .forEach(tagName -> {
                            if (tagNameMap.containsKey(tagName)) {
                                FaceLibPersonTag pTag = new FaceLibPersonTag();
                                if(!tagNameMap.get(tagName).equals(libTag.getTagId())){
                                    pTag.setTagId(Objects.toString(tagNameMap.get(tagName)));
                                    if (null == person.getTagList()) {
                                        person.setTagList(Lists.newArrayList());
                                    }
                                    person.getTagList().add(pTag);
                                }
                            } else {
                                missTagNames.add(tagName);
                            }
                        });

            }
            if(person.getTagEntityList()==null){
                person.setTagEntityList(new ArrayList<>());
            }
            person.getTagList().add(libTag);
            int i = 0;
            try {
                i = this.baseAddFaceLibPerson(person, false);
            } catch (Exception e) {
                log.error("批量导入数据时，忽略异常错误:{}",e);
            }
            resultCnt += i;
        }
        if (isNotEmpty(missTagNames)) {
            log.warn("人脸库，批量新增FaceLibPerson时，找不到以下标签:{}", StaticToolConst.COMMA_JOINER.join(missTagNames));
        }


        this.updateFaceLibTotal(libId);
        log.info("人脸库，批量新增FaceLibPerson后，更新关联FaceLib的total数量。LibId:{}，操作结果:{}", libId, resultCnt);

        return resultCnt;
    }

    @Override
    @Transactional
    public int updateFaceLibPerson(FaceLibPerson newLibPerson) {

        // 更新前，查询数据库中原本的记录，比对处理下图片部分的变动，通过后再处理新增和减少的图片链接
        FaceLibPerson updateQuery = new FaceLibPerson();
        updateQuery.setId(newLibPerson.getId());
        List<FaceLibPerson> updateQueryList = faceLibDao.selectFaceLibPerson(updateQuery);
        if (updateQueryList.isEmpty()) {
            log.error("人脸库，更新FaceLibPerson前，查询发现该记录找不到。LibId:{}", newLibPerson.getLibId());
            throw new RuntimeException("找不到人员记录ID:" + newLibPerson.getId());
        }
        FaceLibPerson dbPerson = updateQueryList.get(0);
        // 数据库中原来的图片URLs
        Set<String> dbImgUrls = Optional.ofNullable(dbPerson.getFaceImageUrl())
                .filter(StringUtils::isNotBlank)
                .map(StaticToolConst.COMMA_SPLITTER::splitToList)
                .map(Sets::newHashSet).orElseGet(()->Sets.newHashSet());

        // 参数中的图片URLs
        Collection<String> newUrls = Optional.ofNullable(newLibPerson.getFaceImageUrl())
                .filter(StringUtils::isNotEmpty)
                .map(StaticToolConst.COMMA_SPLITTER::splitToList)
                .map(Sets::newHashSet)
                .orElseGet(()->Sets.newHashSet());

        // 没变的图片
        HashSet<String> remainUrls = Optional.of(dbImgUrls).map(Sets::newHashSet)
                .map(db -> {
                    db.retainAll(newUrls);
                    return db;
                }).get();

        HashSet<String> addImgUrls = Optional.of(newUrls).map(Sets::newHashSet).map(ne -> {
            ne.removeAll(remainUrls);
            return ne;
        }).get();

        HashSet<String> delImgUrls = Optional.of(dbImgUrls).map(Sets::newHashSet).map(db -> {
            db.removeAll(remainUrls);
            return db;
        }).get();

        log.debug("人脸库，更新FaceLibPerson的FaceImageUrl，LibId:{},人脸图片URL新增 {} 张，删除 {} 张"
                , newLibPerson.getLibId(), addImgUrls.size(), delImgUrls.size());

        int i = faceLibDao.updateFaceLibPerson(newLibPerson);
        log.info("人脸库，更新FaceLibPerson，LibId:{},操作结果:{}", newLibPerson.getLibId(), i);

        // 更新人员标签关系
        // 先删除原来的标签关系
        FaceLibPersonTag deleteTagQuery = new FaceLibPersonTag();
        deleteTagQuery.setFacePersonId(newLibPerson.getId());
        FaceLib lib = faceLibDao.selectLibById(newLibPerson.getLibId());
        FaceLibPersonTag libTag = new FaceLibPersonTag();
        libTag.setTagId(lib.getType());
        libTag.setLibId(lib.getLibId());
        libTag.setFacePersonId(newLibPerson.getId());
        AtomicBoolean isHaveTag = new AtomicBoolean(false);
        int beforeCnt = faceLibDao.deleteTag(deleteTagQuery);
        log.info("人脸库，更新FaceLibPerson，先删除原来的人员标签关系，删除参数:{}，操作结果:{}", deleteTagQuery, beforeCnt);
        // 再添加新的标签关系
        Optional.of(newLibPerson).map(FaceLibPerson::getTagList)
                .filter(CollectionUtils::isNotEmpty)
                .ifPresent(tags -> {
                    tags.forEach(tag -> {
                        if(tag.getTagId().equals(libTag.getTagId())){
                            isHaveTag.set(true);
                        }
                        tag.setFacePersonId(newLibPerson.getId());
                        tag.setLibId(newLibPerson.getLibId());

                    });
                    newLibPerson.setTagList(tags);
                });
        if(newLibPerson.getTagEntityList()==null){
            newLibPerson.setTagEntityList(new ArrayList<>());
        }
        if(!isHaveTag.get()){
            newLibPerson.getTagList().add(libTag);
        }
        int afterCnt = faceLibDao.insertTagList(newLibPerson);
        log.info("人脸库，更新FaceLibPerson，再添加新的人员标签关系，操作结果:{}", afterCnt);

        // 处理变更的人脸特征记录
        // 删除部分人脸特征
        Optional.of(delImgUrls).filter(CollectionUtils::isNotEmpty).map(StaticToolConst.COMMA_JOINER::join)
                .map(urls -> {
                    FaceLibPersonFeature f = new FaceLibPersonFeature();
                    f.setUrl(urls);
                    f.setFacePersonId(newLibPerson.getId());
                    return f;
                }).map(faceLibDao::deleteFaceFeatures)
                .ifPresent(cnt -> log.info("人脸库，更新FaceLibPerson，处理要删除的特征部分，操作结果:{}", cnt));
        // 新增部分人脸特征
        Optional.of(addImgUrls).filter(CollectionUtils::isNotEmpty)//.map(JOINER::join)
                .map(urls -> {
                    List<FaceLibPersonFeature> fList = Optional.ofNullable(newLibPerson.getFeatures())
                            .map(List::stream)
                            .map(fs -> fs.filter(f -> urls.contains(f.getUrl())))
                            .get()
                            .collect(Collectors.toList());
                    fList.forEach(f -> f.setFacePersonId(newLibPerson.getId()));
                    return fList;
                })
                .filter(CollectionUtils::isNotEmpty)
                .map(faceLibDao::insertFaceFeatureList)
                .ifPresent(cnt -> log.info("人脸库，更新FaceLibPerson，处理要新增的特征部分，操作结果:{}", cnt));

        //同步更新引擎布控库里的人员
        addOrUpdateToCompreFace(newLibPerson);

        return i;
    }


    @Override
    @Transactional
    public int deleteFaceLibPerson(FaceLibPerson faceLibPerson) {
        List<FaceLibPerson> faceLibPeople = faceLibDao.selectFaceLibPerson(faceLibPerson);

        if (faceLibPeople == null || faceLibPeople.isEmpty()) {
            throw new RuntimeException("人脸库，删除FaceLibPerson，未找到FaceLibPerson");
        }

        faceLibPerson = faceLibPeople.get(0);
        int deleteResult = faceLibDao.deleteFaceLibPersonByIds(faceLibPerson);
        log.info("人脸库，删除FaceLibPerson。Ids:{}; LibId:{}，操作结果:{}", faceLibPerson.getId(), faceLibPerson.getLibId(), deleteResult);

        // 更新人脸库人员数量
        this.updateFaceLibTotal(faceLibPerson.getLibId());
        log.info("人脸库，删除FaceLibPerson后，更新关联FaceLib的total数量。LibId:{}，操作结果:{}", faceLibPerson.getLibId(), deleteResult);

        // 删除人员标签关系
        FaceLibPersonTag deleteTagQuery = new FaceLibPersonTag();
        deleteTagQuery.setFacePersonId(faceLibPerson.getId());
        deleteTagQuery.setLibId(faceLibPerson.getLibId());
        int tagDeleteCount = faceLibDao.deleteTag(deleteTagQuery);
        log.info("人脸库，根据条件删除FaceLibPerson，删除原来的人员标签关系，删除参数:{}，操作结果:{}", deleteTagQuery, tagDeleteCount);

        // 删除人脸特征记录
        FaceLibPersonFeature delFeatureQuery = new FaceLibPersonFeature();
        delFeatureQuery.setFacePersonId(faceLibPerson.getId());
        int featureDeleteCount = faceLibDao.deleteFaceFeatures(delFeatureQuery);
        log.info("人脸库，根据条件删除FaceLibPerson，删除原来的人员人脸特征，删除参数:{}，操作结果:{}", delFeatureQuery, featureDeleteCount);

        // 同步删除引擎布控库里的人员
        List<String> featureIdList = Arrays.asList(faceLibPerson.getId().split(","));
        Map<String, Object> map = new HashMap<>();
        map.put("libId", ShenWangLibPrefix.getLibPrefix() + faceLibPerson.getLibId());
        map.put("featureIdList", featureIdList);

        if (faceLibPerson.getIdCardNo() == null) {
            throw new RuntimeException("人脸库，删除FaceLibPerson，无身份证号码");
        }

        Result<Object> result = engineApi.deleteSubject(faceLibPerson.getIdCardNo());
        if (result.getResultCode() != 200) {
            log.error("人脸库，同步删除引擎布控库里的人员，删除参数:{}，操作结果:{}", map, result.getResultCode());
            throw new RuntimeException("人脸库，同步删除引擎布控库里的人员失败");
        }

        return deleteResult;
    }

    @Override
    public int deleteFaceLibPersonByLibId(String libId) {

        Optional.ofNullable(libId).filter(StringUtils::isNotBlank)
                .orElseThrow(() -> new RuntimeException("参数中libId不能为空"));

        FaceLibPerson param = new FaceLibPerson();
        param.setLibId(libId);
        int pCnt = faceLibDao.deleteFaceLibPersonByLibId(param);

        // 删除人员标签关系
        FaceLibPersonTag deleteTagQuery = new FaceLibPersonTag();
        deleteTagQuery.setLibId(libId);
        int tCnt = faceLibDao.deleteTag(deleteTagQuery);
        log.info("人脸库，根据LibId删除FaceLibPerson，删除原来的人员标签关系，删除参数libId:{}，操作结果:{}", libId, tCnt);

        // 删除人脸特征记录，TODO 撤控
        int fCnt = faceLibDao.deleteFaceFeaturesByLibId(libId);
        log.info("人脸库，根据LibId删除FaceLibPerson，删除原来的人员特征记录，删除参数libId:{}，操作结果:{}", libId, fCnt);

        return pCnt;
    }

    /**
     * @return 清空缓存的数量
     * @Description: 清空缓存(标签缓存)
     */
    @Override
    public int flushCache() {
        Long size = TagCache.size();
        TagCache.invalidateAll();
        return size.intValue();
    }

    /**
     * @param list 人员信息,[{libId:"",idCardNo:"",addFacePicPaths:""}]
     * @return 数据库操作结果
     * @Description: 图片批量导入，根据libId和idCardNo更新人员信息图片属性
     */
    @Override
    public int updateFaceLibPersonList(List<FaceLibPerson> list) {
        Assert.isTrue(list.stream().map(FaceLibPerson::getLibId).filter(StringUtils::isEmpty).count() == 0
                , "批量更新人员信息时，集合中不能有LibId为空的对象");
        Assert.isTrue(list.stream().map(FaceLibPerson::getIdCardNo).filter(StringUtils::isEmpty).count() == 0
                , "批量更新人员信息时，集合中不能有IdCardNo为空的对象");
        Assert.isTrue(list.stream().map(FaceLibPerson::getFaceImageUrl).filter(StringUtils::isEmpty).count() == 0
                , "批量更新人员信息时，集合中不能有AddFacePicPaths为空的对象");

        // libId
        Set<String> inputLibIds = Optional.of(list.stream().map(FaceLibPerson::getLibId)
                .filter(StringUtils::isNotBlank).collect(Collectors.toSet())).get();
        Assert.isTrue(inputLibIds.size() == 1, "批量更新人员信息时，一次只能操作一个人脸库。参数中发现有LibId:" + inputLibIds);
        String libId = inputLibIds.iterator().next();
        Assert.isTrue(Optional.of(libId).map(bid -> {
            FaceLib lib = new FaceLib();
            lib.setLibId(bid);
            return this.listFaceLibs(lib).getTotalRow() == 1;
        }).get(), "批量更新人员信息时，数据库中找不到人脸库LibId:" + libId);


        // 数据库中找不到的证件号
        final Set<String> missCardNoSet = Sets.newHashSet();

        // 根据libId、idCardNo查询id，设值到对象中
        Optional.of(list).map(personList -> {
            FaceLibPerson param = new FaceLibPerson();
            Optional.of(libId).ifPresent(param::setLibId);
            Optional.of(personList.stream().map(FaceLibPerson::getIdCardNo).collect(Collectors.toSet()))
                    .map(StaticToolConst.COMMA_JOINER::join).ifPresent(param::setIdCardNo);
            List<FaceLibPerson> dbPersonList = faceLibDao.selectFaceLibPersonByLibIdAndIdCardNo(param);
            final Map<String, String> idCardAndIdMap = dbPersonList.stream()
                    .collect(Collectors.toMap(FaceLibPerson::getIdCardNo, FaceLibPerson::getId, (oldVal, newVal) -> newVal));
            personList.stream().forEach(p -> {
                String key = p.getIdCardNo();
                if (idCardAndIdMap.containsKey(key)) {
                    p.setId(idCardAndIdMap.get(key)); // 找到数据库中id，赋值，用作后续update的where条件
                } else {
                    missCardNoSet.add(key); // 找不到的证件号稍后做日志提示
                }
            });
            return idCardAndIdMap;
        }).orElse(Maps.newHashMap());
        Optional.of(missCardNoSet).filter(CollectionUtils::isNotEmpty)
                .ifPresent(miss -> log.warn("数据库中找不到的记录。LibId:{},IdCardNo:{}", libId, missCardNoSet));


        // 收集所有图片URL，组装FaceLibPersonFeature对象集合。赋值faceFeatureId,url
        List<FaceLibPersonFeature> newFeatures = new ArrayList<>(list.size());
        list.stream().forEach(p -> {
            Optional.ofNullable(p.getFaceImageUrl())
                    .map(StaticToolConst.COMMA_SPLITTER::splitToList)
                    .ifPresent(lst -> {
                        lst.stream().map(uri -> new FaceLibPersonFeature(p.getId(), uri))
                                .forEach(newFeatures::add);
                    });
            Optional.ofNullable(p.getFaceImageUrl())
                    .ifPresent(p::setFaceImageUrl);

        });


        //同步到引擎的数据
        List<FeatureData> dataList = Lists.newArrayList();

        // 提取特征，赋值features,md5
        Optional.of(newFeatures).ifPresent(featList -> {
            List<String> urlList = featList.stream().map(FaceLibPersonFeature::getUrl).collect(Collectors.toList());
            Result<Map<String, String>> result = faceEngineService.detectFaceFeature(urlList);
            if (result.getResultCode() == 200) {
                Map<String, String> urlAndFeatMap = result.getData();
                featList.forEach(feat -> {
                    feat.setFeature(urlAndFeatMap.get(feat.getUrl()));
                    feat.caclMd5IfHasFeature();
                    //封装特征数据，准备去同步到引擎
                    FeatureData data = new FeatureData();
                    data.setId(feat.getFacePersonId());
                    data.setData(feat.getFeature());
                    dataList.add(data);
                });
            } else {
                log.error("调用引擎服务提取特征失败。Code:{},Msg:{}", result.getResultCode(), result.getResultMessage());
            }
        });

        // 保存人脸特征记录到数据库
        Optional.of(newFeatures).filter(CollectionUtils::isNotEmpty).ifPresent(featList -> {
            int fCnt = faceLibDao.insertFaceFeatureList(newFeatures);
            log.info("保存人脸库人员人脸特征记录，操作结果:{}", fCnt);
        });


        //同步到引擎的布控库中
        HashMap map = Maps.newHashMap();
        map.put("libId",ShenWangLibPrefix.getLibPrefix()+libId);
        map.put("dataList",JSON.toJSON(dataList).toString());
        Result result = faceLibApi.addLibFeatureBatch(map);
        log.info("人脸库，同步新增引擎布控库里的人员，操作结果:{}，操作结果:{}", map,result.getResultCode());

        // 更新人员信息，更新FaceImageUrl
        Integer cnt = list.stream().map(faceLibDao::updateFaceLibPerson)
                .reduce((i, j) -> i + j).get();
        log.info("批量更新人脸库人员信息，操作结果:{}\r\n参数:{}", cnt, JSONObject.toJSONString(list));

        return cnt;
    }

    @Override
    public int updateFaceLibPersonPic(List<FaceLibPerson> personList) {
        return faceLibDao.updateFaceLibPersonPic(personList);
    }

}
